//////////////////////////////////////////////////////////////////////////
//
// This file is a part of UKROP project.
// Copyright (c) Vladimir Gumenuk
//
// PROJECT:         Xort Custom Debug Engine
// FILE:            StackFrame.h : Declaration of the CStackFrame
// AUTHOR:          Vladimir Gumenuk
// DATE:            Dec-2012 -- Jan-2013
// MODIFICATIONS:
//
//////////////////////////////////////////////////////////////////////////

#pragma once

//////////////////////////////////////////////////////////////////////////
// CStackFrame
class ATL_NO_VTABLE CStackFrame :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CStackFrame, &CLSID_StackFrame>,
    public IDebugStackFrame2,
    public IDebugExpressionContext2,
    public IXStackFrame
{
public:
    CStackFrame();
    virtual ~CStackFrame();

DECLARE_REGISTRY_RESOURCEID(IDR_TISTACKFRAME)

BEGIN_COM_MAP(CStackFrame)
    COM_INTERFACE_ENTRY(IDebugStackFrame2)
    COM_INTERFACE_ENTRY(IDebugExpressionContext2)
    COM_INTERFACE_ENTRY(IXStackFrame)
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

IMPLEMENT_CREATE(CStackFrame, IDebugStackFrame2)

    HRESULT FinalConstruct();
    void FinalRelease();

    //////////////////////////////////////////////////////////////////////////
    // IXStackFrame
    STDMETHOD(Init)( IDebugDocumentContext2 *pDocContext, IDebugProgram2 *pProgram, UINT64 addrMin, UINT64 addrMax, FRAMEINFO *pFrameInfo );
    STDMETHOD(AddProperty)( IDebugProperty2 *pProperty );
    STDMETHOD(PushPropertyList)();
    STDMETHOD(PopPropertyList)();
    STDMETHOD(UnInit)();

    //////////////////////////////////////////////////////////// 
    // IDebugStackFrame2 
    STDMETHOD(GetCodeContext)( IDebugCodeContext2 **ppCodeCxt ); 
    STDMETHOD(GetDocumentContext)( IDebugDocumentContext2 **ppCxt ); 
    STDMETHOD(GetName)( BSTR* pbstrName ); 
    STDMETHOD(GetInfo)( FRAMEINFO_FLAGS dwFieldSpec, UINT nRadix, FRAMEINFO *pFrameInfo ); 
    STDMETHOD(GetPhysicalStackRange)( UINT64* paddrMin, UINT64* paddrMax ); 
    STDMETHOD(GetExpressionContext)( IDebugExpressionContext2 **ppExprCxt ); 
    STDMETHOD(GetLanguageInfo)( BSTR* pbstrLanguage, GUID* pguidLanguage ); 
    STDMETHOD(GetDebugProperty)( IDebugProperty2 **ppDebugProp ); 
    STDMETHOD(EnumProperties)( DEBUGPROP_INFO_FLAGS dwFields, UINT nRadix, REFGUID guidFilter, DWORD dwTimeout, ULONG *pcelt, IEnumDebugPropertyInfo2 **ppepi ); 
    STDMETHOD(GetThread)( IDebugThread2** ppThread ); 

    //////////////////////////////////////////////////////////////////////////
    // IDebugExpressionContext2
    STDMETHOD(ParseText)( LPCOLESTR pszCode, PARSEFLAGS dwFlags, UINT nRadix, IDebugExpression2 **ppExpr, BSTR *pbstrError, UINT *pichError );

private:
    HRESULT CreateRegistersInfo( IXEnumPropertyInfo *pXEnum, UINT nRadix );
    void FormatRegister( const XortElement& xCell, int iIndex, UINT nRadix, CPropertyInfo **ppPropOut );

    CComPtr<IDebugProgram2>             m_spProgram;
    CComPtr<IDebugDocumentContext2>     m_spDocCtx;

    UINT64                              m_addrMin;  // lowest physical address associated with this stack frame, actually - stack base for this proc 
    UINT64                              m_addrMax;  // IDE assumes, that stack grows down, so we have to return it as m_addrMin < m_addrMax!

    CFrameInfo                         *m_pFrameInfo;

    CFramePropertyStack                 m_stackProps;
    PROPERTIES_LIST::iterator           m_theIter;
};

OBJECT_ENTRY_AUTO(__uuidof(StackFrame), CStackFrame)

//////////////////////////////////////////////////////////////////////////
// Stack frames information
class ATL_NO_VTABLE CEnumFrameInfo :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CEnumFrameInfo, &CLSID_EnumFrameInfo>,
    public IEnumDebugFrameInfo2,
    public IXEnumFrameInfo
{
public:
    CEnumFrameInfo();
    virtual ~CEnumFrameInfo();

DECLARE_REGISTRY_RESOURCEID(IDR_ENUMFRAMEINFO)

BEGIN_COM_MAP(CEnumFrameInfo)
    COM_INTERFACE_ENTRY(IEnumDebugFrameInfo2)
    COM_INTERFACE_ENTRY(IXEnumFrameInfo)
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

IMPLEMENT_CREATE(CEnumFrameInfo, IEnumDebugFrameInfo2)

    HRESULT FinalConstruct();
    void FinalRelease();

    //////////////////////////////////////////////////////////////////////////
    // IXEnumFrameInfo
    STDMETHOD(AddFrameInfo)( FRAMEINFO *pFrameInfo );

    //////////////////////////////////////////////////////////// 
    // IEnumDebugFrameInfo2 
    STDMETHOD(Next)( ULONG celt, FRAMEINFO *rgelt, ULONG* pceltFetched ); 
    STDMETHOD(Skip)( ULONG celt ); 
    STDMETHOD(Reset)(); 
    STDMETHOD(Clone)( IEnumDebugFrameInfo2** ppEnum ); 
    STDMETHOD(GetCount)( ULONG* pcelt ); 

private:
    typedef CFrameInfo*     LPFRAMEINFO;
    typedef xlist< LPFRAMEINFO, CCopyObject<LPFRAMEINFO>, CDeleteObject<LPFRAMEINFO> >   FRAMEINFO_LIST;
    FRAMEINFO_LIST              m_listFrames;
    FRAMEINFO_LIST::iterator    m_theIter;
};

OBJECT_ENTRY_AUTO(__uuidof(EnumFrameInfo), CEnumFrameInfo)

//////////////////////////////////////////////////////////////////////////
// CEnumDebugPropertyInfo
class ATL_NO_VTABLE CEnumDebugPropertyInfo :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CEnumDebugPropertyInfo, &CLSID_EnumDebugPropertyInfo>,
	public IEnumDebugPropertyInfo2,
    public IXEnumPropertyInfo
{
public:
	CEnumDebugPropertyInfo();
	virtual ~CEnumDebugPropertyInfo();

DECLARE_REGISTRY_RESOURCEID(IDR_ENUMDEBUGPROPERTYINFO)

BEGIN_COM_MAP(CEnumDebugPropertyInfo)
	COM_INTERFACE_ENTRY(IEnumDebugPropertyInfo2)
    COM_INTERFACE_ENTRY(IXEnumPropertyInfo)
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

IMPLEMENT_CREATE(CEnumDebugPropertyInfo, IXEnumPropertyInfo)

	HRESULT FinalConstruct();
	void FinalRelease();

    STDMETHOD(AddProperty)( DEBUG_PROPERTY_INFO *pProp ); // actually internal CPropertyInfo passed!

public:
    STDMETHOD(Next)( ULONG celt, DEBUG_PROPERTY_INFO *rgelt, ULONG *pceltFetched );
    STDMETHOD(Skip)( ULONG celt );
    STDMETHOD(Reset)();
    STDMETHOD(Clone)( IEnumDebugPropertyInfo2 **ppEnum );
    STDMETHOD(GetCount)( ULONG *pcelt );

    typedef CPropertyInfo* LPPROPERTYINFO;
    typedef xlist< LPPROPERTYINFO, CCopyObject<LPPROPERTYINFO>, CDeleteObject<LPPROPERTYINFO> >   PROPERTYINFO_LIST;
    PROPERTYINFO_LIST               m_listProperties;
    PROPERTYINFO_LIST::iterator     m_theIter;
};

OBJECT_ENTRY_AUTO(__uuidof(EnumDebugPropertyInfo), CEnumDebugPropertyInfo)
